/**
 * @file BM77SSP03.c
 * @brief bluetooth Interface
 *
 * @version Fixed
 * @author lbx
 * @date 2014-05-04
 */
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/err.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "config.h"
#include "console.h"
#include "bt_cmd.h"
#include "device.h"

typedef enum{
	BT_STAUS_SHUTDOWN = 0x1001,
	BT_STAUS_ACCESS,
	BT_STAUS_LINK,
}bt_status_t;

#define bt_wake_up()		ioctl(bt_fd, IOCTL_BT_WAKE_UP, NULL)
#define bt_advertising()	ioctl(bt_fd, IOCTL_BT_ADV, NULL)
#define bt_disconnect()		ioctl(bt_fd, IOCTL_BT_LINK_DROP, NULL)
#define bt_mode(mode)		ioctl(bt_fd, IOCTL_BT_MODE_CTL, mode)
#define bt_status()			ioctl(bt_fd, IOCTL_GET_BT_STATUS, NULL)

static void bt_get_laddr(int argc, const char **argv);
static void bt_get_name(int argc, const char **argv);
#if 0
static void bt_set_wakeup(int argc, const char **argv);
#endif

static void bt_set_mode(int argc, const char **argv);
static void bt_get_status(int argc, const char **argv);
static void bt_set_adv(int argc, const char **argv);
static void bt_set_disconnect(int argc, const char **argv);

static bt_info_t bt_info;
static char bt_retbuf[64];
static int bt_fd = -1;

const command_t BT_CMD[] = {
	{"+ADV", bt_set_adv, NULL},
	{"+DISC", bt_set_disconnect, NULL},
	{"+STATUS", bt_get_status,NULL},
	{"#CSMODE", bt_set_mode, NULL},
	{"+LADDR", bt_get_laddr, NULL},
	{"+NAME", bt_get_name, NULL},
#if 0		
	{"+WAKE", bt_set_wakeup, NULL},
#endif
};

int bt_get_bt_cmd_num(void) 
{
    return sizeof(BT_CMD) / sizeof(BT_CMD[0]);
}

void bt_dev_init(void)
{
    uint8_t rbuf[128];
    int i, name_flag = 0, mac_flag = 0;
    uint32_t start, ms = 2000;
    
    bt_fd = open(CONFIG_BT_DEV, O_RDWR|O_NONBLOCK);
    bt_retfunc_free();
	memset(bt_retbuf, 0, sizeof(bt_retbuf));
    memset(&bt_info, 0, sizeof(bt_info));
    
    bt_mode(1);
    start = timeout_start(0);
    while(!timeout_test(&start, &ms)) {
        if (!name_flag) {
            serial_write(CONFIG_BT_UART, 
                "\x01\x29\xFC\x03\x00\x0B\x10", 7);
            serial_read(CONFIG_BT_UART, rbuf, 26, 1000);
            if (!strcmp("\x04\x0E\x17\x01\x29\xFC\x00\x00\x0B\x10", rbuf)) {
                memcpy(bt_info.name, rbuf + 10, 16);
                name_flag = 1;
            }
        }
        if (!mac_flag) {
            serial_write(CONFIG_BT_UART, 
                "\x01\x29\xFC\x03\x00\x00\x06", 7);
            serial_read(CONFIG_BT_UART, rbuf, 16, 1000);
            if (!strcmp("\x04\x0E\x0D\x01\x29\xFC\x00\x00\x00\x06", rbuf)) {
                for (i = 0; i < 6; i++)
                    bt_info.mac[i] = rbuf[15 - i];
                mac_flag = 1;
            }
        }

        if (name_flag && mac_flag)
            break;
    }
    bt_mode(0);
    bt_disconnect();
    bt_cmd_reg(BT_CMD, sizeof(BT_CMD) / sizeof(BT_CMD[0]));
}

int bt_info_read(bt_info_t * rbuf)
{
    if (rbuf == NULL)
        return -EINVAL;

    strcpy(rbuf->name, bt_info.name);
    memcpy(rbuf->mac, bt_info.mac, 6);
    
    return 0;
}

static int bt_retprintf(uint8_t * buffer, size_t len)
{
	len = len > strlen(bt_retbuf) ? strlen(bt_retbuf) + 1 : len;
	memcpy(buffer, bt_retbuf, len);

	return len;
}

int bt_is_enable(void)
{
	bt_status_t state;
	
	state = bt_status();
	if(state < BT_STAUS_SHUTDOWN || state > BT_STAUS_LINK)
		return 0;	
	else 
		return state - BT_STAUS_SHUTDOWN;
}

static void bt_set_adv(int argc, const char **argv)
{
	if (argc != 1) {
		strcpy(bt_retbuf, "ERROR\r\n");
        bt_retfunc_reg(bt_retprintf);
	}
	else {
		bt_advertising();
		strcpy(bt_retbuf, "OK\r\n");
		bt_retfunc_reg(bt_retprintf);
        serial_clrbuf(CONFIG_BT_UART, 1, 1);
	}
}

static void bt_set_disconnect(int argc, const char **argv)
{
	if (argc != 1) {
		strcpy(bt_retbuf, "ERROR\r\n");
		bt_retfunc_reg(bt_retprintf);
	}
	else {
		bt_disconnect();
		strcpy(bt_retbuf, "OK\r\n");
		bt_retfunc_reg(bt_retprintf);
	}
}

static void bt_get_laddr(int argc, const char **argv)
{
	if (argc != 1) {
		strcpy(bt_retbuf, "ERROR\r\n");
		bt_retfunc_reg(bt_retprintf);
	}
	else {
		sprintf(bt_retbuf, 
            "+LADDR=%02x:%02x:%02x:%02x:%02x:%02x\r\nOK\r\n",
            bt_info.mac[0], 
            bt_info.mac[1], 
            bt_info.mac[2], 
            bt_info.mac[3], 
            bt_info.mac[4], 
            bt_info.mac[5]);
		bt_retfunc_reg(bt_retprintf);
	}
}

static void bt_get_name(int argc, const char **argv)
{
	if (argc != 1) {
		strcpy(bt_retbuf, "ERROR\r\n");
		bt_retfunc_reg(bt_retprintf);
	}
	else {
		sprintf(bt_retbuf, "+NAME=\"%s\"\r\nOK\r\n", bt_info.name);
		bt_retfunc_reg(bt_retprintf);
	}
}

#if 0
static void bt_set_wakeup(int argc, const char **argv)
{
	if (argc != 1) {
		strcpy(bt_retbuf, "ERROR\r\n");
		bt_retfunc_reg(bt_retprintf);
	}
	else {
		bt_wake_up();
		strcpy(bt_retbuf, "OK\r\n");
		bt_retfunc_reg(bt_retprintf);
	}
}
#endif

static void bt_set_mode(int argc, const char **argv)
{
	if (argc != 2) {
		strcpy(bt_retbuf, "ERROR\r\n");
		bt_retfunc_reg(bt_retprintf);
	}
	else {
		uint32_t mode = strtol(argv[1], NULL, 10);
#ifdef CONFIG_POWER_CTL        
        if (mode)
            enter_bt_mode();
        else
            exit_bt_mode();
#endif        
		bt_mode(mode);
		strcpy(bt_retbuf, "OK\r\n");
		bt_retfunc_reg(bt_retprintf);
        mdelay(1);
        if (mode == 0)
            serial_clrbuf(CONFIG_BT_UART, 1, 1);
	}
 
}


static void bt_get_status(int argc, const char **argv)
{
	bt_status_t state;
	
	if (argc != 1) {
		strcpy(bt_retbuf, "ERROR\r\n");
		bt_retfunc_reg(bt_retprintf);
	}
	else {
		state = bt_status();
		if(state < BT_STAUS_SHUTDOWN || state > BT_STAUS_LINK)
			strcpy(bt_retbuf, "ERROR\r\n");
		else {
			sprintf(bt_retbuf, "+STATUS=%d\r\nOK\r\n", state - BT_STAUS_SHUTDOWN);
		}
		bt_retfunc_reg(bt_retprintf);
	}
}

int bt_write(uint8_t * buffer, size_t len)
{
    return serial_write(CONFIG_BT_UART, buffer, len);
}

int bt_read(uint8_t * buffer, size_t len, int timeout)
{
    return serial_read(CONFIG_BT_UART, buffer, len, timeout);
}

void bt_clrbuf(void) 
{
    serial_clrbuf(CONFIG_BT_UART, 1, 1);
}



